package me.xiaolei.andlog.interceptor.impls

import me.xiaolei.andlog.comm.InterceptorChain
import me.xiaolei.andlog.comm.LogType
import me.xiaolei.andlog.interceptor.IInterceptor
import java.io.File
import java.io.RandomAccessFile
import java.text.SimpleDateFormat
import java.util.Calendar

/**
 * 使用本地文件API保存日志
 */
object DiskInterceptor : IInterceptor
{
    // 日期格式
    private val dateTimeFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS")

    // 回车换行
    private val ENTER = "\r\n".toByteArray()

    // 启用
    var enable: Boolean = false

    // 日志保存文件夹
    var logDir: File? = null

    /**
     * 生成的日志文件的格式
     *
     * 年 -> {y}
     * 月 -> {M}
     * 日 -> {d}
     * 时 -> {H}
     * 分 -> {m}
     * 秒 -> {s}
     * 毫秒 -> {S}
     * 下标 -> {I}
     */
    var fileNamePattern = "{y}-{M}-{d} {H}:{m}:{s} {S}"

    // 日志文件的后缀
    var logFileSuffix = "log"

    // 日志文件的最大size,默认是8M
    var maxLogSize: Long = 1024 * 1024 * 8

    // 最后写入的文件
    private var lastFile: RandomAccessFile? = null

    override fun intercept(chain: InterceptorChain)
    {
        try
        {
            val logDir = logDir
            // 不启用直接跳过
            if (!enable || logDir == null)
                return
            // 文件夹不存在，并且文件夹创建失败直接跳过
            if (!logDir.exists() && !logDir.mkdirs())
                return
            // 创建日志信息
            val logStr = buildLogString(chain)
            val logByteArray = logStr.toByteArray()
            // 获取最后的文件
            // 如果没有，就新建一个，如果有，则查看文件大小，如果超出最大，则新建一个新文件
            val lastFile = when (val file = lastFile)
            {
                null ->
                {
                    val newFile = newLogFile(chain.time)
                    lastFile = newFile
                    newFile
                }
                else ->
                {
                    if (file.length() + logByteArray.size + ENTER.size > maxLogSize)
                    {
                        file.close()
                        val newFile = newLogFile(chain.time)
                        lastFile = newFile
                        newFile
                    } else
                    {
                        file
                    }
                }
            }
            // 写入文件
            lastFile.write(logByteArray)
            lastFile.write(ENTER)
        } catch (e: Exception)
        {
            e.printStackTrace()
        } finally
        {
            chain.proceed()
        }
    }

    /**
     * 根据传入的信息，创建对应的日志信息
     */
    private fun buildLogString(chain: InterceptorChain): String
    {
        val builder = java.lang.StringBuilder()

        val timeFormat = dateTimeFormat.format(chain.time.time)
        val tag = chain.tag
        val msg = chain.msg
        val type = chain.type

        builder.append(timeFormat)
        builder.append("\t")
        builder.append(
            when (type)
            {
                LogType.DEBUG -> "D/"
                LogType.INFO -> "I/"
                LogType.WARNING -> "W/"
                LogType.ERROR -> "E/"
                LogType.VERBOSE -> "V/"
            }
        )
        builder.append(tag)
        builder.append(" ")
        builder.append(msg)

        return builder.toString()
    }

    /**
     * 新建日志文件
     */
    private fun newLogFile(time: Calendar): RandomAccessFile
    {
        // 生成日志文件名
        val logFileName = parseFileName(fileNamePattern, time)
        // 生成对应的文件
        val logFile = File(logDir, "$logFileName.$logFileSuffix")
        // 如果有对应的文件存在，则删除原文件
        if (logFile.exists())
        {
            logFile.delete()
        }
        // 随机读写文件
        return RandomAccessFile(logFile, "rw")
    }

    /**
     * 解析文件名字
     */
    private fun parseFileName(pattern: String, time: Calendar): String
    {
        // 提取时间的年月日时分秒毫秒
        val year = time.get(Calendar.YEAR)
        val month = time.get(Calendar.MONTH) + 1
        val day = time.get(Calendar.DAY_OF_MONTH)
        val hour = time.get(Calendar.HOUR_OF_DAY)
        val minute = time.get(Calendar.MINUTE)
        val second = time.get(Calendar.SECOND)
        val millis = time.get(Calendar.MILLISECOND)

        return pattern.replace("{y}", year.toString())
            .replace("{M}", month.toString())
            .replace("{d}", day.toString())
            .replace("{H}", hour.toString())
            .replace("{m}", minute.toString())
            .replace("{s}", second.toString())
            .replace("{S}", millis.toString())
    }
}